package com.qiusuo0226.self.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qiusuo0226.common.constant.NumConstant;
import com.qiusuo0226.common.util.ConvertTool;
import com.qiusuo0226.mvc.util.JsonResultModel;
import com.qiusuo0226.security.config.SecurityProperty;
import com.qiusuo0226.security.util.AesTool;
import com.qiusuo0226.security.util.JWTTool;
import com.qiusuo0226.self.exceptions.PasswordManageEncryptExcetion;
import com.qiusuo0226.self.mapper.PasswordManageMapper;
import com.qiusuo0226.self.pojo.dto.PasswordManageAddDTO;
import com.qiusuo0226.self.pojo.dto.PasswordManageEditDTO;
import com.qiusuo0226.self.pojo.dto.PasswordManagePageDTO;
import com.qiusuo0226.self.pojo.entity.PasswordManageDO;
import com.qiusuo0226.self.pojo.query.PasswordManageSearchBean;
import com.qiusuo0226.self.pojo.vo.PasswordManageVO;
import com.qiusuo0226.self.service.PasswordManageService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.Map;

/**
 * 个人密码管理 逻辑层 实现
 * @author qiusuo
 * @date 2023/7/15 22:27
 */
@Service
@Slf4j
public class PasswordManageServiceImpl extends ServiceImpl<PasswordManageMapper, PasswordManageDO> implements PasswordManageService {

    @Autowired
    private SecurityProperty property;

    @Override
    public JsonResultModel add (PasswordManageAddDTO dto) {
        log.debug("新增个人密码管理：{}", dto.toString());
        try {
            // token校验
            verifyCreater(dto.getCreater(), dto.getToken());
        } catch (Exception e) {
            return JsonResultModel.failure(NumConstant.S30001, "生成token的id和创建人的id不一致，创建一条个人密码管理失败");
        }

        PasswordManageDO entity = new PasswordManageDO();
        entity.setSoftwareName(dto.getSoftwareName());
        entity.setWebsite(dto.getWebsite());
        entity.setAccount(dto.getAccount());
        entity.setDescription(dto.getDescription());
        entity.setTags(dto.getTags());
        entity.setCreater(dto.getCreater());
        entity.setEncryptType(dto.getEncryptType());


        // 数据库加密存储方式
        try {
            entity.setPassword(encryptPwd(dto.getEncryptType(), dto.getPassword(), dto.getEncryptKeyInfo()));
            entity.setEncryptKeyInfo(dto.getEncryptKeyInfo() == null ? "" : dto.getEncryptKeyInfo().toJSONString());
        } catch (PasswordManageEncryptExcetion e) {
            return JsonResultModel.failure(NumConstant.S30002, "密码加密异常：" + e.getMessage());
        }
        baseMapper.insert(entity);

        return JsonResultModel.success("新增成功");
    }

    @Override
    public JsonResultModel edit(PasswordManageEditDTO dto) {
        log.debug("编辑个人密码管理：{}", dto.toString());
        try {
            // token校验
            verifyCreater(dto.getCreater(), dto.getToken());
        } catch (Exception e) {
            return JsonResultModel.failure(NumConstant.S30001, "生成token的id和创建人的id不一致，编辑一条个人密码管理失败");
        }

        PasswordManageDO entity = new PasswordManageDO();
        entity.setIid(dto.getIid());
        entity.setSoftwareName(dto.getSoftwareName());
        entity.setWebsite(dto.getWebsite());
        entity.setAccount(dto.getAccount());
        entity.setDescription(dto.getDescription());
        entity.setTags(dto.getTags());
        entity.setCreater(dto.getCreater());
        entity.setEncryptType(dto.getEncryptType());

        // 数据库加密存储方式
        try {
            entity.setPassword(encryptPwd(dto.getEncryptType(), dto.getPassword(), dto.getEncryptKeyInfo()));
            entity.setEncryptKeyInfo(dto.getEncryptKeyInfo() == null ? "" : dto.getEncryptKeyInfo().toJSONString());
        } catch (PasswordManageEncryptExcetion e) {
            return JsonResultModel.failure(NumConstant.S30002, "密码加密异常：" + e.getMessage());
        }

        int effectRows = baseMapper.updateById(entity);
        return effectRows > 0 ? JsonResultModel.success("编辑成功") : JsonResultModel.failure("编辑失败");
    }

    @Override
    public PasswordManagePageDTO list(PasswordManageSearchBean bean) {
        Page<PasswordManageVO> page = new Page(bean.getPageNo(), bean.getPageSize());
        IPage<PasswordManageVO> iPage = baseMapper.list(page, bean);

        // 分页结果组装
        PasswordManagePageDTO pageDTO = new PasswordManagePageDTO();
        pageDTO.setPageNo(iPage.getCurrent());
        pageDTO.setPageSize(iPage.getSize());
        pageDTO.setTotal(iPage.getTotal());
        pageDTO.setList(iPage.getRecords());
        return pageDTO;
    }

    @Override
    public JsonResultModel remove(String iids, Long creater) {
        // 删除的数量
        int deleteNum = baseMapper.deleteBatchIds(Arrays.asList(iids.split(",")));
        return deleteNum > 0 ? JsonResultModel.success("删除成功") : JsonResultModel.failure("删除失败");
    }

    /**
     * 验证创建者唯一标识
     * 只有当创建者唯一标识和token中的iid保持一致时，才能证明当前修改人和token登录获取人是在同一页面，操作才能进行
     * @param creater 创建者唯一标识
     * @param token 验证的token
     */
    public void verifyCreater (long creater, String token) throws Exception {
        cn.hutool.json.JSONObject verify = JWTTool.verify(token, property.getJwtKey());
        Long tokenId = verify.getLong("iid");
        if (creater != tokenId.longValue()) {
            throw new Exception("生成token的id和创建人的id不一致，个人密码管理失败");
        }
    }

    /**
     * 加密密码
     * @param type 加密方式
     * @param password 加密密码
     * @param config 加密所需要的配置
     * @return 加密结果
     */
    public String encryptPwd (String type, String password, Map config) throws PasswordManageEncryptExcetion {
        switch (type) {
            case NumConstant.S0:
                // 当 type = 0 ， 使用系统默认aes ecb模式加密存库
                byte[] bytes = new byte[0];
                try {
                    bytes = AesTool.encryptECB(password, ConvertTool.hexToBytes(property.getAesKey()));
                } catch (Exception e) {
                    log.error("个人密码管理默认aes ecb模式加密异常", e);
                    throw new PasswordManageEncryptExcetion("个人密码管理默认aes ecb模式加密异常");
                }
                return ConvertTool.base64EncodeToStr(bytes);
            case NumConstant.S1:
                // 当 type = 1 时，使用自定义key的aes ecb模式加密存库
                if (null == config) {
                    throw new PasswordManageEncryptExcetion("加密配置缺失");
                }
                // AES ECB模式加密密钥
                String key = MapUtils.getString(config, "key", "");
                if (StringUtils.isBlank(key)) {
                    throw new PasswordManageEncryptExcetion("加密密钥缺失");
                }
                byte[] miwen = new byte[0];
                try {
                    miwen = AesTool.encryptECB(password, ConvertTool.hexToBytes(key));
                } catch (Exception e) {
                    log.error("个人密码管理自定义aes ECB模式加密异常", e);
                    throw new PasswordManageEncryptExcetion("个人密码管理自定义aes ECB模式加密异常");
                }
                return ConvertTool.base64EncodeToStr(miwen);
            default:
                return "";
        }
    }
}
